asynx.namespace("drag");

asynx.drag = function() {
	this.init(arguments);
};

asynx.drag.prototype = {
	
	init: function(arguments) {
		this.el = asynx(arguments[0]);
		this.dX = 0;
		this.dY = 0;
		this.ntop = 0;
		this.nleft = 0;
		this.mouse = [];
		this.zIframe = null;
		this.zIndex = asynx.globals.drag.lastzIndex++;
		this.draggable = true;
		this.resizable = true;
		this.dragging = false;
		this.dragHandle = null;
		this.clickTarget = null;
		this.initDrag();
	},
	
	initDrag: function() {
		var el = this.el;
		var t = el.css("top"), l = el.css("left"),
			w = el.css("width"), h = el.css("height");
		
		el.css({
			position:'absolute',
			zIndex:this.zIndex,
			top:t,
			left:l,
			width:w,
			height:h
		});
		
		el.mousedown(this._onStartDrag, [this]);
		el.mouseup(this._onEndDrag, [this]);
	},
	
	_onStartDrag: function(e, args) {
		
		var scope = args[0], ta = scope.clickTarget = e.target,
			dH = scope.dragHandle, moveScope = asynx.isIE?asynx('/html'):document;
			
		dH = scope.dragHandle = dH?dH:ta;
		scope.dragging = true;
		scope.findDelta(e);
		
		// drag by dragArea child
		asynx.dom.walkParents(ta,function(p){if(p==dH)ta=scope.clickTarget=dH;});
		
		// prevent scroll bug
		var w = asynx.stripUnit(scope.el.css('width'));
		var h = asynx.stripUnit(scope.el.css('height'));
		
		if (scope.el.scrollWidth>w||scope.el.scrollHeight>h) {
			var clickPosX = w-scope.dX;
			var clickPosY = h-scope.dY;
			var scrolls = {ie:23,ff:13,safari:3};
			var b = asynx.isIE||asynx.isOpera?'ie':(asynx.isFirefox?'ff':(asynx.isSafari?'safari':20));
			var scrollsize = scrolls[b];
			if (clickPosX<scrollsize||clickPosY<scrollsize) return false;
		}
		
		// onmove
		asynx.event.mousemove(moveScope, scope._onDrag, [scope]);
		
		// disable text selection
		asynx.disableSelection(asynx('/body'));
		
		// user
		if (scope.onStartDrag && ta==dH)
			scope.onStartDrag.apply(scope, [scope.el, e]);
	},
	
	_onDrag: function(e, args) {
		var scope = args[0];
		var el = scope.el, dH = scope.dragHandle, ta = scope.clickTarget;
		var m = scope.mouse = asynx.event.getMouseXY(e);
		var l = scope.nleft = scope.mouse[0]-scope.dX;
		var t = scope.ntop = scope.mouse[1]-scope.dY;
		
		// drag area condition
		if (ta!=dH) return;
		
		if (scope.dragging && scope.draggable) {
			asynx.setXY(el, l, t);
			if (scope.zIframe) scope.setXY(scope.zIframe, l, t);
		};

		
		// user
		if (scope.onDrag)
			scope.onDrag.apply(scope, [el, e]);
	},
	
	_onEndDrag: function(e, args) {
		var scope = args[0], dH = scope.dragHandle, ta = scope.clickTarget;
		scope.dragging = false;
		
		var moveScope = asynx.isIE?asynx('/html'):document;
		asynx.event.remove('mousemove', moveScope, scope._onDrag, [scope]);
		
		// enable text selection
		asynx.enableSelection(asynx('/body'));
		
		// user
		if (scope.onEndDrag && (ta==dH||!dH))
			scope.onEndDrag.apply(scope, [scope.el, e]);
	},
	
	setDraggable: function(b) {
		this.draggable = b;
	},
	
	setDragHandle: function(el) {
		this.dragHandle = asynx(el);
		this._disableChildSelection(this.dragHandle);
	},
	
	_disableChildSelection: function(el) {
		try {
			asynx.dom.walk(el, function(node) {
				if (asynx.dom.isTextNode(node)) return;
				asynx.disableSelection(node);
			});
		}
		catch(e) {}
	},
	
	_enableChildSelection: function(el) {
		try {
			asynx.dom.walk(el, function(node) {
				if (asynx.dom.isTextNode(node)) return;
				asynx.enableSelection(node);
			});
		}
		catch(e) {}
	},
	
	setDragArea: function(el) {
		
	},
	
	setOnTop: function(b) {
		var el = this.el;
		var z = this.zIndex;
		if (b) z = asynx.globals.drag.lastzIndex++;
		el.css({zIndex:z});
	},
	
	fixzIndex: function() {
		// fix zIndex ie 
		if (asynx.isIE && !this.zIframe)
			this.zIframe = asynx.fixzIndex(this.el);
	},
	
	findDelta: function(e) {
		this.mouse = asynx.event.getMouseXY(e);
		this.dX = this.mouse[0] - (this.el.css("left")||0.0);
		this.dY = this.mouse[1] - (this.el.css("top")||0.0);
	}
};
